package pluginUtils;

import java.io.PrintStream;
import java.util.Random;

import pluginUtils.DupinCyclide.CyclideType;

/** un cercle de Villarceau sur une cyclide **/
public class CiclydeVillarceauCircle {
	/** La cyclide de Dupin sur laquelle s'inscrit le cercle de Villarceau **/
	protected DupinCyclide genesis; 
	
	/** L' angle definissant le cercle **/
	protected double th;
	
	/** Vaut -1 ou 1, un des deux cercles **/
	protected double epsi;
	
	
	private static Random generator=new Random(); 
	
	public CiclydeVillarceauCircle(DupinCyclide genesis, double th,
			double epsi) {
		super();
		this.genesis = genesis;
		this.th = th;
		this.epsi = epsi;
		this.initValues(); 
	} 
	
	private double a; 
	private double c; 
	private double mu;
	private double k=500; 
	
	/* Un paquet de calculs intermediaires */
	private double w,b,den,r,R,xw; 
	
	public double getA(){return this.genesis.getA(); }
	public double getMu(){ return this.genesis.getMu(); }
	public double getC(){return this.genesis.getC(); }
	
	private void initValues(){
		a=this.getA(); 
		c=this.getC();
		mu=this.getMu(); 
		b=Math.sqrt(a*a-c*c); 
		w=(a*mu+b*Math.sqrt(mu*mu-c*c))/c; 
		
		//System.out.println("a,b,c,mu "+a+" "+b+" "+c+" "+mu);
		//System.out.println("Omega "+w); 
		den=(a-c)*(mu-c)+b*Math.sqrt(mu*mu-c*c);
		k=den;
		//System.out.println("den :"+den); 
		r=k*c*c*(mu-c)/(den*((a+c)*(mu-c)+b*Math.sqrt(mu*mu-c*c))); 
		R=k*c*c*(a-c)/(den*((a-c)*(mu+c)+b*Math.sqrt(mu*mu-c*c)));
		//System.out.println("R r "+R+" "+r); 
		double aux1=(a-c)*(mu+w)-b*b; 
		double aux2=(a+c)*(w-mu)+b*b;  // w-c dans le papier
		xw=w-(k*b*b*(w-c)/(aux1*aux2));
		
		//System.out.println("x_omega "+xw); 
	}
	
	private double den1(double t){
		double terme1=Math.sqrt(R*R-r*r)*Math.cos(th)*Math.sin(t);
		double terme2=epsi*(r+R*Math.cos(t))*Math.sin(th); 
		double somme= xw-terme1-terme2-w; 
		//System.out.println("den1("+t+")"+(somme*somme));
		return somme*somme; 
	}
	
	private double den2(double t){
		double terme1=Math.sqrt(R*R-r*r)*Math.sin(th)*Math.sin(t);
		double terme2=epsi*(r+R*Math.cos(t))*Math.cos(th); 
		double somme= -terme1+terme2; 
		//System.out.println("den2("+t+")"+(somme*somme));
		return somme*somme; 
	}
	
	private double numx(double t){
		double terme1=Math.sqrt(R*R-r*r)*Math.cos(th)*Math.sin(t); 
		double terme2=epsi*(r+R*Math.cos(t))*Math.sin(th); 
		return -terme1-terme2; 
		
	}
	private double denom(double t){
		return den1(t)+den2(t)+r*r*Math.sin(t)*Math.sin(t); 
	}
	
	private double valX(double t){
		double numer=k*(xw-w+numx(t)); 
		double fraction=numer/denom(t); 
		//System.out.println("ValX("+t+"):"+(w+fraction)); 
		return w+fraction; 
	}
	
	private double valY(double t){
		double terme1=Math.sqrt(R*R-r*r)*Math.sin(th)*Math.sin(t);
		double terme2=epsi*(r+R*Math.cos(t))*Math.cos(th); 
		//System.out.println("ValY("+t+"):"+(k*(-terme1+terme2)/denom(t))); 
		return k*(-terme1+terme2)/denom(t); 
	}
	
	private double valZ(double t){
		//System.out.println("ValZ("+t+"):"+k*r*Math.sin(t)/denom(t));
		return k*r*Math.sin(t)/denom(t); 
	}
	
	public Pos3D getPoint(double t){
		return new Pos3D(valX(t),valY(t),valZ(t)); 
	}
	
	public Circle3D getCircle3D(){
		//output.println("getCircle3D"); 
		Pos3D p1=this.getPoint(0); 
		Pos3D p2=this.getPoint(Math.PI/3);
		Pos3D p3=this.getPoint(2*Math.PI/3);
		Circle3D prov=Circle3D.buildCircle3D(p1, p2, p3);
		return prov; 
	}
	
	public void verifyCenter(){
		
		for(int i=0;i<20;i++){
			Pos3D p1=this.getPoint(2*Math.PI*generator.nextDouble()); 
			Pos3D p2=this.getPoint(2*Math.PI*generator.nextDouble());
			Pos3D p3=this.getPoint(2*Math.PI*generator.nextDouble());
			Circle3D prov=Circle3D.buildCircle3D(p1, p2, p3);
			System.out.println(prov.getCenter()+"\t"+prov.getRayon()); 
		}
	}
	
	public Plane getPlane(){
		//output.println("getPlane"); 
		Pos3D p1=this.getPoint(0); 
		Pos3D p2=this.getPoint(Math.PI/3);
		Pos3D p3=this.getPoint(2*Math.PI/3);
		Circle3D prov=Circle3D.buildCircle3D(p1, p2, p3);
		return prov.getPlan(); 
	}
	
	public static void main(String[] args) throws Exception {
		//PrintStream output=new PrintStream("/tmp/planesExtended.txt");
		double a=5; 
		double mu=3; 
		double c=1; 
		DupinCyclide dc=new DupinCyclide(a,mu,c); 
		
		int end=10; 
		for(int i=0;i<end;i++){
		double a1=2*i*Math.PI/end; 	
		CiclydeVillarceauCircle cv=new CiclydeVillarceauCircle(dc,a1,1);
		//Plane lePlan=cv.getPlane();
		Circle3D leCercle=cv.getCircle3D(); 
		System.out.println(i); 
		Pos3D center=cv.getCircle3D().getCenter(); 
		double rayon=cv.getCircle3D().getRayon(); 
		Pos3D p1=cv.getPoint(0); 
		Pos3D p2=cv.getPoint(Math.PI); 
		Pos3D V1=Pos3D.sub(p1, center); 
		Pos3D V2=Pos3D.sub(p2, center);
		double pscal=V2.produitScalaire(V1); 
		double theta=Math.acos(pscal/(rayon*rayon));
		System.out.println("t=0 "+cv.getPoint(0)); 
		System.out.println("t=PI "+cv.getPoint(Math.PI)); 
		System.out.println("Centre : "+center); 
		System.out.println("Rayon : "+rayon+" circonference "+(2*Math.PI*rayon));
		System.out.println(theta/(2*Math.PI)) ;
		
		cv=new CiclydeVillarceauCircle(dc,a1,-1);
		
		leCercle=cv.getCircle3D(); 
		
		center=cv.getCircle3D().getCenter(); 
		rayon=cv.getCircle3D().getRayon(); 
		p1=cv.getPoint(0); 
		p2=cv.getPoint(Math.PI); 
		V1=Pos3D.sub(p1, center); 
		V2=Pos3D.sub(p2, center);
		pscal=V2.produitScalaire(V1); 
		theta=Math.acos(pscal/(rayon*rayon));
		System.out.println("\t t=0 "+cv.getPoint(0)); 
		System.out.println("\t t=PI "+cv.getPoint(Math.PI)); 
		System.out.println("\t Centre : "+center); 
		System.out.println("\t Rayon : "+rayon+" circonference "+(2*Math.PI*rayon));
		System.out.println("\t"+theta/(2*Math.PI)) ;
		
		}
		
		/*
		
		int end=3; 
		for(int i=0;i<end;i++){
		double a1=2*i*Math.PI/end; 	
		CiclydeVillarceauCircle cv=new CiclydeVillarceauCircle(dc,a1,1);
		//Plane lePlan=cv.getPlane();
		Circle3D leCercle=cv.getCircle3D(); 
		System.out.println(i+" "+leCercle.rawString()); 
		output.println(leCercle.rawString()); 
		}
		for(int i=0;i<end;i++){
			double a1=2*i*Math.PI/end; 	
			CiclydeVillarceauCircle cv=new CiclydeVillarceauCircle(dc,a1,-1);
			Circle3D leCercle=cv.getCircle3D(); 
			//Plane lePlan=cv.getPlane(); 
			System.out.println(i+" "+leCercle.rawString()); 
			output.println(leCercle.rawString()); 
			}
		
		output.close(); 
		*/
		
		}	
}

